package cn.smile.auth.service.impl;

import cn.smile.auth.service.LoginService;
import cn.smile.bean.dto.core.SysUserDTO;
import cn.smile.bean.form.login.LoginForm;
import cn.smile.bean.form.login.LoginInfoForm;
import cn.smile.bean.form.login.LoginPhoneForm;
import cn.smile.business.core.ISysUserService;
import cn.smile.commons.constant.NumberConstant;
import cn.smile.commons.constant.RedisKeyConstant;
import cn.smile.commons.enums.core.UserStatusEnum;
import cn.smile.commons.exceptions.BusinessException;
import cn.smile.commons.response.MyResponseCode;
import cn.smile.commons.web.Header;
import cn.smile.utils.*;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import jakarta.annotation.Resource;
import java.util.UUID;

/**
 * @author smile-jt
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private ISysUserService userService;
    @Resource
    private RedisUtil redisUtil;

    @Override
    public String loginSys(HttpServletRequest request, LoginForm form) {
        log.info("[LoginServiceImpl].[loginSys] 登录系统 Start, form = {}", JSON.toJSONString(form));
        SysUserDTO dto = userService.queryByLogin(form.getUsername());
        if (ObjectUtils.isEmpty(dto)) {
            this.loginError(request);
            throw new BusinessException(MyResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        if (UserStatusEnum.ENABLE != UserStatusEnum.get(dto.getStatus())) {
            throw new BusinessException(MyResponseCode.USER_DISABLED_ERROR);
        }
        String encode = PasswordUtil.encrypt(form.getPassword());
        if (!dto.getPassword().equals(encode)) {
            this.loginError(request);
            throw new BusinessException(MyResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        String token = this.getToken(dto);
        log.info("[LoginServiceImpl].[loginSys] 登录系统 End, token = {}", token);
        return token;
    }

    @Override
    public String loginPhone(HttpServletRequest request, LoginPhoneForm form) {
        log.info("[LoginServiceImpl].[loginPhone] 登录系统 Start, form = {}", JSON.toJSONString(form));
        SysUserDTO dto = userService.queryByPhone(form.getPhone());
        if (ObjectUtils.isEmpty(dto)) {
            this.loginError(request);
            throw new BusinessException(MyResponseCode.USERNAME_OR_PASSWORD_ERROR);
        }
        LoginForm loginForm = BeanCopy.copyBean(form, LoginForm.class);
        loginForm.setUsername(dto.getLoginId());
        String token = this.loginSys(request, loginForm);
        log.info("[LoginServiceImpl].[loginPhone] 登录系统 End, token = {}", token);
        return token;
    }

    @Override
    public void refreshEff() {
        log.info("[LoginServiceImpl].[refreshEff] 刷新 Token 有效期 Start");
        String tokenKey = Header.getToken();
        String redisKey = String.format(RedisKeyConstant.USER_TOKEN_KEY, tokenKey);
        Object tokenBucket = redisUtil.get(redisKey);
        if (!ObjectUtils.isEmpty(tokenBucket)) {
            // 设置token缓存有效时间
            redisUtil.set(redisKey, tokenBucket, RedisKeyConstant.USER_TOKEN_TIMEOUT);
        }
        log.info("[LoginServiceImpl].[refreshEff] 刷新 Token 有效期 End");
    }

    @Override
    public Boolean logoutSys() {
        log.info("[LoginServiceImpl].[logoutSys] 注销登录 Start");
        String token = Header.getToken();
        redisUtil.del(String.format(RedisKeyConstant.USER_TOKEN_KEY, token));
        log.info("[LoginServiceImpl].[logoutSys] 注销登录 End");
        return Boolean.TRUE;
    }

    /**
     * 登录账号或密码错误
     *
     * @param request 请求
     */
    private void loginError(HttpServletRequest request) {
        //获取请求 IP 地址
        String ip = IpUtils.getRemoteIp(request);
        String redisKey = String.format(RedisKeyConstant.SUSPEND_VISIT_IP_NUM_KEY, ip);
        //获取 Redis 已经记录的次数
        Object bucket = redisUtil.get(redisKey);
        int num = NumberConstant.ZERO;
        if (!ObjectUtils.isEmpty(bucket)) {
            num = (Integer) bucket;
        }
        //错误次数累加
        ++num;
        redisUtil.set(redisKey, num, RedisKeyConstant.SUSPEND_VISIT_IP_NUM_TIMEOUT);
    }

    /**
     * 获取Token
     *
     * @param dto 用户对象
     * @return 获取结果
     */
    private String getToken(SysUserDTO dto) {
        String tokenKey = UUID.randomUUID().toString();
        //有效7天
        redisUtil.set(String.format(RedisKeyConstant.USER_TOKEN_KEY, tokenKey), JSON.toJSONString(dto), RedisKeyConstant.USER_TOKEN_TIMEOUT);
        LoginInfoForm form = new LoginInfoForm();
        //登录成功, 更新最后登录信息
        HttpServletRequest req = SpringContextUtils.getHttpServletRequest();
        if (!ObjectUtils.isEmpty(req)) {
            form.setLastLoginAddress(IpUtils.getRemoteIp(req));
            form.setId(dto.getId());
            userService.updateLoginTime(form);
        }
        return tokenKey;
    }
}
